#include "DXUT.h"

#include "ClusterChunk.h"
#include "World.h"

Cluster::~Cluster() {
	for (int i = 0; i < 16; i++) {
		SAFE_DELETE( pChunks[i] );
	}
}

Cluster::Cluster(void* world, int x, int z) {
	_x = x * 16;
	_z = z * 16;
	pWorld = world;

	Heightmap	*map  = new Heightmap(16, 16, x, z);
	Cavemap		*cave = new Cavemap(0.02f, 0.60f, x, z);

	for (int y = 0; y < 16; ++y) {
		pChunks[y] = new Chunk(this, _x, _z, y * 16);
	}


	int height[256];
	for (int i = 0; i < 16; i++) {
		for (int j = 0; j < 16; j++) {
			height[i + (j << 4)] = floor((map->getHeight(i, j) + 1) * 64) + 20;
		}
	}
	for (int y = 15; y >= 0; --y) {
		pChunks[y]->generateBlocks(height, cave);
	}

	delete map;
	delete cave;
}

void Cluster::lightPass() {
	// first lightpass
	for (int i = 0; i < 16; i++) {
		pChunks[i]->calculateLight();
	}
}

void Cluster::lightPass2() {
	// snd, reverse lightpass
	for (int i = 15; i >= 0; i--) {
		pChunks[i]->calculateLight2();
	}
}

void Cluster::resetLight() {
	char height[256];
	for (int i = 15; i >= 0; i--) {
		pChunks[i]->resetLight(height);
	}
}

void Cluster::render(const D3DXVECTOR3 * eye, const D3DXVECTOR3 * dir, ID3D11DeviceContext* pImmediateContext) {
	D3DXVECTOR3 * vec = &D3DXVECTOR3(_x + 8.0f, eye->y, _z + 8.0f);
	D3DXVec3Subtract(vec, vec, eye);
	if (D3DXVec3Length(vec) > g_Renderdistance*2) return;

	if (D3DXVec3Length(vec) > 20.0f) {
		D3DXVec3Normalize(vec,vec);
		//D3DXVECTOR3 * flatDir = &D3DXVECTOR3(dir->x, 0.0f, dir->z);
		if (D3DXVec3Dot(vec, dir) < -(1-D3DXVec3Dot(dir, &D3DXVECTOR3(dir->x, 0.0f, dir->z)))) return;
	}
	for (int i = 0; i < 15; i++) {
		pChunks[i]->render(eye, dir, pImmediateContext);
	}
}

void Cluster::generateVB(ID3D11Device* pd3dDevice) {
	for (int i = 0; i < 15; i++) {
		pChunks[i]->generateVB(pd3dDevice);
	}
}

void Cluster::Release() {
	for (int i = 0; i < 15; i++) {
		pChunks[i]->Release();
	}
}

Block Cluster::getBlock(int x, int z, int y) {
	if (y > 255) {
		Block block = {0, 15};
		return block;
	} 
	if (y < 0) {
		Block block = {255, 0};
		return block;
	} 
	if ((x > 15 + _x) || (z > 15 + _z) || (x < _x) || (z < _z)) {
		return reinterpret_cast<World*>(pWorld)->getBlock(x, z, y);
	} else {
		x = x - ((x >> 4) << 4);
		z = z - ((z >> 4) << 4);
		return pChunks[y >> 4]->getBlock(x, z, y % 16);
	} 
}

void Cluster::setBlock(int x, int z, int y, Block block) {
	if ((x > 15 + _x) || (z > 15 + _z) || (x < _x) || (z < _z)) {
		reinterpret_cast<World*>(pWorld)->setBlock(x, z, y, block);
	} else {
		x = x - ((x >> 4) << 4);
		z = z - ((z >> 4) << 4);
		pChunks[y >> 4]->setBlock(x, z, y % 16, block);
	} 
}